package nl.science.uva.pico;

import java.util.LinkedList;
import java.util.List;

import nl.science.uva.pico.operand.Operand;

/** 
 * Stack contains the data for the stack language programs. It's a classic LIFO stack with some additional
 * 
 * @author Ivo van Dongen, Karel Pieterson
 * @version 1.0
 */
public class Stack {
		
	private static final String SEPERATOR_CHARACTER = " ";
	private List<Operand> source;

	public Stack() {
		//Use a linked list since most operations will work from the tail
		this.source = new LinkedList<Operand>();
	}
	
	/** 
	 * Put operand on top of stack
     *  
     *  @param Operand
     *  
     */		
	public void push(Operand operand) {
		source.add(operand);
	}
	
	/** 
	 * Get value from top of stack
     *  
     *  @return Operand
     *  @throws IllegalStateException
     */		
	public Operand pop() {
		if(!source.isEmpty()) {
			int lastIndex = source.size() - 1;
			Operand operand = source.get(lastIndex);
			source.remove(lastIndex);
			return operand;
		} else {
			throw new IllegalStateException("Stack is empty");
		}
	}
	
	/** 
	 * Copy value at index in stack to top of stack; 
     *  
     *  @return Operand
     *  @param index of Operand
     *  @throws IllegalArgumentException
     */		
	public Operand get(int index) {
		if(index >= source.size()) {
			throw new IllegalArgumentException("Stack contains less entries than index: " + index);
		}
		
		Operand operand = source.get(index);
		return operand;
	}
	
	/** 
	 * Delete value at index from stack
     *  
     *  @param index of Operand
     *  @return Operand
     */		
	public Operand remove(int index) {
		Operand operand = get(index);
		source.remove(index);
		return operand;
	}
	
	/** 
	 * Put value at index in stack
	 *  
     *  @param Operand
     *  @param index of Operand
     *  
     *  @throws IllegalArgumentException
     *  
     */		
	public void store(Operand operand, int index) {
		if(index > source.size()) {
			throw new IllegalArgumentException("Stack contains less entries than index: " + index);
		}
		
		source.set(index, operand);
	}
	
	/** 
	 * Return number of entries on the stack
     *  
     *  @return integer
     */		
	public int size() {
		return source.size();
	}
	
	/** 
	 * Return Stack as a String
     *  
     *  @return String
     */		
	@Override
	public String toString() {
		StringBuilder toStringContents = new StringBuilder();
		for (Operand operand : source) {
			toStringContents.append("{");
			toStringContents.append(operand);
			toStringContents.append("}");
			toStringContents.append(SEPERATOR_CHARACTER);
		}
		return toStringContents.toString();
	}
}
